from manimlib import *
import random as rd
# needs to import MyTriangle
r=2**0.5*0.2

def equalnote(start,end,ticks,color=WHITE):
    line=Line(start,start/2+end/2,color=color,stroke_width=2).rotate(PI/2)
    line.scale(0.1/line.get_length())
    vg1=VGroup(*[line.copy().shift(normalize(end-start)*0.05*i) for i in range(ticks)]).move_to(start*0.75+end*0.25)
    vg2=vg1.copy().move_to(start*0.25+end*0.75)
    return VGroup(vg1,vg2)

def equal(equalnotes,anim=ShowCreation):
    return AnimationGroup(*[anim(equalnotes[i]) for i in [0,1]])

def rdarray(x_min,x_max,y_min,y_max):
    return np.array([rd.uniform(x_min,x_max),rd.uniform(y_min,y_max),0])

class MyTrianglePro(MyTriangle):
    def get_midpoints(self): # 各边中点
        """
        输出为点A所对中点，点B所对中点，点C所对中点
        """
        A, B, C = Polygon.get_vertices(self)
        return [(B+C)/2,(C+A)/2,(A+B)/2]
    
    def get_drop_feet(self): # 各高垂足 
        """
        垂足
                垂足(drop foot)是临床上常见的现象，其正式的名称是踝关节蹠屈(equinus foot)。正常的踝关节可以进行背屈(dorsiflexion) 、蹠屈(plantar flexion)、内翻(inversion)、外翻(eversion)等动作。当背屈的动作变差，便会出现垂足现象。正常步态需要有健全的踝关节功能，一旦发生垂足现象，就会有各种代偿性步态出现，例如骨盆上扬(hip hiking)是利用提高骨盆来避免足部拖地；跨阈步态(steppage gait)是利用更多的髋关节屈曲和膝关节屈曲来延长足部离地时间；健侧的脚可能出现跳跃现象(vaulting)来帮助患脚离地。症状较轻微的病患，可能会出现患脚以前足(forefoot)著地或足部拍击地面(foot slap)的情形。有些病人并不自觉，而经常性地发生绊倒。患有垂足的病人，行走不但耗能而且危险,这是我们必须正视它的原因。
        """
        A, B, C = Polygon.get_vertices(self)
        a, b, c = self.get_side_length()
        AngleA, AngleB, AngleC = self.get_three_angle()
        Ax, Ay = A[0], A[1]
        Bx, By = B[0], B[1]
        Cx, Cy = C[0], C[1]
        H_A=B*(1-c*np.cos(AngleB)/a)+C*c*np.cos(AngleB)/a
        H_B=C*(1-a*np.cos(AngleC)/b)+A*a*np.cos(AngleC)/b
        H_C=A*(1-b*np.cos(AngleA)/c)+B*b*np.cos(AngleA)/c
        return [H_A,H_B,H_C]
    
    def get_midlines(self):
        """
        获得中线
        """
        A, B, C = Polygon.get_vertices(self)
        lines=[Line(p,mp,color=YELLOW) for p,mp in zip([A,B,C],self.get_midpoints())]
        return VGroup(*lines)
    
    def get_heights(self):
        """
        获得垂线
        """
        A, B, C = Polygon.get_vertices(self)
        lines=[Line(p,mp,color=YELLOW) for p,mp in zip([A,B,C],self.get_drop_feet())]
        return VGroup(*lines)
    
    def get_circle_mids(self):
        H=self.get_orthocenter()
        return [2*i-H for i in self.get_midpoints()]
    
    def get_circle_feet(self):
        H=self.get_orthocenter()
        return [2*i-H for i in self.get_drop_feet()]

def right_angle(corner,side):
    sq=Square(r,fill_opacity=0,stroke_width=2)
    sq.next_to(corner,UR,buff=0)
    coor=side-corner
    angle=math.atan2(coor[1],coor[0])
    sq.rotate(angle,about_point=corner)
    return sq

class construct_scene1(Scene):
    def construct(self):
        triangle=MyTrianglePro(np.array([-2,-1,0]),np.array([2,-1,0]),np.array([1,2,0]),color=BLUE,fill_opacity=0.5,stroke_width=5)#!!
        self.play(ShowCreation(VGroup(triangle)),run_time=2)
        A=Tex("A").next_to(np.array([-2,-1,0]),DL)#!!
        B=Tex("B").next_to(np.array([2,-1,0]),DR)#!!
        C=Tex("C").next_to(np.array([1,2,0]),UP)#!!
        vg=VGroup(A,B,C)#!!
        self.play(Write(vg))
        

        heights=triangle.get_heights()#!! heights[0] needs to be changed!
        垂心=Dot(triangle.get_orthocenter(),color=GREEN)#!!
        H=Tex("H").next_to(垂心,UR)
        self.wait()
        self.play(*[ShowCreation(l) for l in heights])
        self.wait()
        self.play(heights.animate.set_color(WHITE),Write(垂心))
        self.play(Write(H))
        self.wait()
        kw={"stroke_width":3,"radius":r}
        angleB=Angle(*[Dot(triangle.get_vertices()[i]) for i in [1,0,2]],**kw,color=MAROON)#角B
        angleH=Angle(Dot(triangle.get_drop_feet()[1]),垂心,Dot(triangle.get_drop_feet()[2]),**kw,color=ORANGE)#以H为顶点的角（担任3个角的任务）
        right_angle_C=right_angle(triangle.get_drop_feet()[2],triangle.get_vertices()[2])#C点垂足
        right_angle_B=right_angle(triangle.get_drop_feet()[1],triangle.get_vertices()[0])#B点垂足
        self.play(*[ShowCreation(i) for i in [angleB,angleH,right_angle_C,right_angle_B]],H.animate.set_opacity(0.1))
        self.wait()
        anglesum=VGroup(angleB.copy(),Tex("+"),angleH.copy(),Tex("="),Tex(r"180^\circ")).arrange().to_edge(DOWN)
        anglesum.add_updater(lambda m:m.become(VGroup(angleB.copy(),Tex("+"),angleH.copy(),Tex("="),Tex(r"180^\circ")).arrange().to_edge(DOWN)))
        self.play(TransformMatchingShapes(VGroup(angleB.copy(),angleH.copy()),anglesum))
        self.wait()

        self.play(Rotating(angleH,angle=PI,about_point=triangle.get_orthocenter(),rate_func=smooth,run_time=1))
        self.wait()

        BHC=Line(triangle.get_vertices()[1],triangle.get_orthocenter()).add_line_to(triangle.get_vertices()[2])#!! flip needed!
        self.add(BHC)
        self.bring_to_front(垂心,angleH)
        BC_vec=normalize(triangle.get_vertices()[2]-triangle.get_vertices()[1])#!! flip needed!
        H_A_dot=Dot(BHC.get_all_points()[2],color=GREEN)#!! filp needed!
        self.play(
            BHC.animate.flip(axis=BC_vec,about_point=triangle.get_drop_feet()[0]),#!!
            angleH.copy().animate.flip(axis=BC_vec,about_point=triangle.get_drop_feet()[0]),#!!
            H_A_dot.animate.flip(axis=BC_vec,about_point=triangle.get_drop_feet()[0]),#!!
            H.animate.next_to(垂心,DL)
        )
        H_A=Tex("H","_A","'").next_to(BHC.get_all_points()[2])#!!
        #H点对称点的标记（可用作垂足标记）（Transform）
        self.wait()
        self.play(TransformMatchingTex(H.copy(),H_A))
        self.wait()
        self.add(heights[0],垂心,angleB,angleH,H_A_dot)
        foot=Dot(triangle.get_drop_feet()[0],fill_color="#333333",stroke_color=BLUE,stroke_width=2)
        self.play(heights[0].animate.put_start_and_end_on(triangle.get_vertices()[0],BHC.get_all_points()[2]),FadeIn(foot))#!!height[0]
        equalsegments=equalnote(triangle.get_orthocenter(),BHC.get_all_points()[2],1)
        self.play(*[ShowCreation(VGroup(l)) for l in equalsegments])
        self.wait(0.5)
        anglesum.clear_updaters()
        self.play(LaggedStart(*[Indicate(i) for i in anglesum],lag_ratio=0.25))
        circle=triangle.get_circumcircle()
        text=TexText("$A,B,C,H_A'$四点共圆").next_to(anglesum,UP)
        self.wait()
        self.play(Write(text),ShowCreation(circle),run_time=2)
        self.wait()
        self.play(*[FadeOut(i) for i in [angleB,right_angle_B,right_angle_C,anglesum,text]])
        self.wait()

class construct_scene2(Scene):
    def construct(self):
        triangle=MyTrianglePro(np.array([-2,-1,0]),np.array([2,-1,0]),np.array([1,2,0]),color=BLUE,fill_opacity=0.5,stroke_width=5)#!!
        A=Tex("A").next_to(np.array([-2,-1,0]),DL)#!!
        B=Tex("B").next_to(np.array([2,-1,0]),DR)#!!
        C=Tex("C").next_to(np.array([1,2,0]),UP)#!!
        vg=VGroup(A,B,C)#!!
        heights=triangle.get_heights().set_color(WHITE)
        垂心=Dot(triangle.get_orthocenter(),color=GREEN)#!!
        H=Tex("H").next_to(垂心,DL).set_opacity(0.1)
        BHC=Line(triangle.get_vertices()[1],triangle.get_orthocenter()).add_line_to(triangle.get_vertices()[2])#!! flip needed!
        
        angleH=Angle(*[Dot(BHC.get_all_points()[i]) for i in [0,2,4]],stroke_width=3,radius=r,color=ORANGE)
        BHCcopy=VGroup(BHC.copy(),Line(triangle.get_orthocenter(),triangle.get_midpoints()[0]),垂心.copy().scale(0.5),angleH.copy().scale(0.5,about_point=triangle.get_orthocenter()))
        BC_vec=normalize(triangle.get_vertices()[2]-triangle.get_vertices()[1])
        H_A_dot=Dot(BHC.get_all_points()[2],color=GREEN)#!! filp needed!
        BHC.flip(axis=BC_vec,about_point=triangle.get_drop_feet()[0])
        H_A_dot.flip(axis=BC_vec,about_point=triangle.get_drop_feet()[0])
        angleHp=Angle(*[Dot(BHC.get_all_points()[i]) for i in [4,2,0]],stroke_width=3,radius=r,color=ORANGE)
        equalsegments=equalnote(triangle.get_orthocenter(),BHC.get_all_points()[2],1)
        H_A=Tex("H","_A","'").next_to(BHC.get_all_points()[2])
        circle=triangle.get_circumcircle()
        foot=Dot(triangle.get_drop_feet()[0],fill_color="#333333",stroke_color=BLUE,stroke_width=2)
        self.add(triangle,vg,heights,foot,垂心,H,BHC,angleH,angleHp,H_A_dot,equalsegments,H_A,circle)
        heights[0].put_start_and_end_on(triangle.get_vertices()[0],BHC.get_all_points()[2])
        frame=self.camera.frame
        self.wait()
        self.play(frame.animate.move_to(triangle.get_midpoints()[0]).scale(0.5),
        *[VGroup(i,j,k).animate.scale(0.5,about_point=i.get_center()) for i,j,k in [(垂心,H,angleH),(H_A_dot,H_A,angleHp)]],
        foot.animate.scale(0.5)
        )
        midH=BHCcopy[1].copy()
        midA=SmallDot(triangle.get_midpoints()[0],fill_color="#333333",stroke_width=2,stroke_color=BLUE)
        self.add(midH,midA,垂心,angleH,H)
        self.play(FadeIn(midA),ShowCreation(midH),foot.set_opacity,0.1)
        equalsegments2=equalnote(triangle.get_vertices()[1],triangle.get_vertices()[2],1,BLUE)
        for l in equalsegments2:
            l.scale(2)
        self.wait(0.5)
        self.play(equal(equalsegments2))
        self.wait(0.5)
        self.play(equal(equalsegments2,Uncreate),foot.set_opacity,1)
        self.wait()
        self.add(BHCcopy[0],BHCcopy[1],BHCcopy[2],BHCcopy[3],midA,H,H_A)
        self.play(
            *[Rotating(BHCcopy[i],angle=PI,about_point=triangle.get_midpoints()[0],rate_func=smooth) for i in range(4)],
            circle.animate.scale(1.1)
        )
        self.wait()
        equalsegments3=equalnote(triangle.get_orthocenter(),BHCcopy[2].get_center(),2)
        M_A=Tex("M","_A","'").next_to(BHCcopy[2],UR).scale(0.5,about_point=BHCcopy[2].get_center())
        self.play(equal(equalsegments3),Write(M_A))
        self.wait()
        self.play(Indicate(BHCcopy[-1]),Indicate(angleHp))
        self.wait()
        self.play(circle.animate.scale(1/1.1))
        text=TexText("$A,B,C,H_A',M_A'$五点共圆").to_edge(DOWN)
        self.wait()
        self.play(frame.animate.move_to(ORIGIN).scale(2),Write(text),
        *[FadeOut(item) for item in [BHC,BHCcopy[0],BHCcopy[-1],angleH,angleHp]],
        *[VGroup(i,j).animate.scale(2,about_point=i.get_center()) for i,j in [(垂心,H),(H_A_dot,H_A),(BHCcopy[2],M_A)]],
        foot.animate.scale(2),midA.animate.scale(2))
        self.wait()
        self.play(FadeOut(text),M_A.animate.next_to(BHCcopy[2],UR))
        self.wait()

class construct_scene3(Scene):
    def construct(self):
        triangle=MyTrianglePro(np.array([-2,-1,0]),np.array([2,-1,0]),np.array([1,2,0]),color=BLUE,fill_opacity=0.5,stroke_width=5)#!!
        A=Tex("A").next_to(np.array([-2,-1,0]),DL)#!!
        B=Tex("B").next_to(np.array([2,-1,0]),DR)#!!
        C=Tex("C").next_to(np.array([1,2,0]),UP)#!!
        vg=VGroup(A,B,C)#!!
        heights=triangle.get_heights().set_color(WHITE)
        垂心=Dot(triangle.get_orthocenter(),color=GREEN)#!!
        H=Tex("H").next_to(垂心,DL).set_opacity(0.1)
        BHCcopy=VGroup(Line(triangle.get_orthocenter(),triangle.get_midpoints()[0]),垂心.copy()).rotate(PI,about_point=triangle.get_midpoints()[0])
        BHCcopy[0].scale(2,about_point=BHCcopy[1].get_center())
        BC_vec=normalize(triangle.get_vertices()[2]-triangle.get_vertices()[1])
        H_A_dot=Dot(triangle.get_orthocenter(),color=GREEN)#!! filp needed!
        H_A_dot.flip(axis=BC_vec,about_point=triangle.get_drop_feet()[0])
        midA=Dot(triangle.get_midpoints()[0],fill_color="#333333",stroke_width=2,stroke_color=BLUE)
        equalsegments=equalnote(triangle.get_orthocenter(),H_A_dot.get_center(),1)
        H_A=Tex("H","_A","'").next_to(H_A_dot.get_center())
        circle=triangle.get_circumcircle()
        foot=Dot(triangle.get_drop_feet()[0],fill_color="#333333",stroke_color=BLUE,stroke_width=2)
        equalsegments3=equalnote(triangle.get_orthocenter(),BHCcopy[1].get_center(),2)
        M_A=Tex("M","_A","'").next_to(BHCcopy[1],UR)
        self.add(triangle,vg,heights,foot,circle,H_A_dot,equalsegments,H_A,BHCcopy[0],BHCcopy[1],midA,M_A,equalsegments3,垂心,H)
        heights[0].put_start_and_end_on(triangle.get_vertices()[0],H_A_dot.get_center())
        frame=self.camera.frame
        mids=VGroup(*[Dot(i,fill_color="#333333",stroke_color=BLUE,stroke_width=2) for i in triangle.get_midpoints()[1:]])
        feet=VGroup(*[Dot(i,fill_color="#333333",stroke_color=BLUE,stroke_width=2) for i in triangle.get_drop_feet()[1:]])
        circlemids=VGroup(*[Dot(i,color=GREEN) for i in triangle.get_circle_mids()[1:]])
        circlefeet=VGroup(*[Dot(i,color=GREEN) for i in triangle.get_circle_feet()[1:]])
        circlemidlines=VGroup(*[Line(triangle.get_orthocenter(),c) for c in triangle.get_circle_mids()[1:]])
        midlineequals=VGroup(*[equalnote(triangle.get_orthocenter(),c,1) for c in triangle.get_circle_mids()[1:]])
        footlineequals=VGroup(*[equalnote(triangle.get_orthocenter(),c,2) for c in triangle.get_circle_feet()[1:]])
        #heights[1].put_start_and_end_on(triangle.get_vertices()[1],triangle.get_circle_feet()[1])
        #heights[2].put_start_and_end_on(triangle.get_vertices()[2],triangle.get_circle_feet()[2])
        #self.add(circlemidlines,circlemids,circlefeet,midlineequals,footlineequals,H,垂心)
        self.add(circlemidlines[0],circlemidlines[1],H,垂心)
        self.play(ShowCreation(circlemidlines[0]),ShowCreation(circlemidlines[1]),FadeIn(mids))
        self.play(*[ReplacementTransform(垂心.copy(),dot) for dot in circlemids])
        
        self.play(equal(midlineequals[0]),equal(midlineequals[1]))
        self.add(heights[1],heights[2],H,垂心)
        self.play(
            heights[1].animate.put_start_and_end_on(triangle.get_vertices()[1],triangle.get_circle_feet()[1]),
            heights[2].animate.put_start_and_end_on(triangle.get_vertices()[2],triangle.get_circle_feet()[2]),
            FadeIn(feet)
        )
        self.play(*[ReplacementTransform(垂心.copy(),dot) for dot in circlefeet])
        self.play(equal(footlineequals[0]),equal(footlineequals[1]))
        M_B=Tex("M","_B","'").next_to(circlemids[0],LEFT)
        M_C=Tex("M","_C","'").next_to(circlemids[1],DOWN)
        H_B=Tex("H","_B","'").next_to(circlefeet[0],UL)
        H_C=Tex("H","_C","'").next_to(circlefeet[1],DOWN)
        self.wait()
        self.add(垂心,H)
        self.play(*[Write(i) for i in [M_B,M_C,H_B,H_C]],H.animate.set_opacity(1).move_to(垂心))
        text=TexText("同理，我们有$A,B,C,H_A',M_A',H_B',M_B',H_C',M_C'$九点共圆").to_edge(DOWN)
        self.wait()
        self.play(Write(text))
        vectices=VGroup(*[Dot(i,color=BLUE) for i in triangle.get_vertices()])
        HVmids=VGroup(*[Dot(i/2+triangle.get_orthocenter()/2,fill_color="#333333",stroke_color=BLUE,stroke_width=2) for i in triangle.get_vertices() for i in triangle.get_vertices()])
        
        self.wait()
        self.play(FadeIn(vectices),FadeIn(HVmids))
        self.wait(2)
        text2=TexText("我们让这些点关于垂心$H$缩小$\\frac12$").to_edge(DOWN)
        self.play(FadeOut(text),Write(text2))
        self.wait(3)
        VG=VGroup(H_A,H_B,H_C,M_A,M_B,M_C,A.copy(),B.copy(),C.copy(),circle.copy(),H_A_dot,*circlefeet,BHCcopy[1],*circlemids,*vectices,)
        self.add(heights,feet,foot,HVmids,circlemidlines,BHCcopy[0],mids,midA,垂心,H,VG)
        self.play(VG.animate.scale(0.5,about_point=triangle.get_orthocenter()),*[FadeOut(i) for i in [midlineequals,footlineequals,circlemidlines,equalsegments,equalsegments3,BHCcopy[0]]],
        heights.animate.become(triangle.get_heights().set_color(WHITE)),run_time=5)
        Relist=VGroup(Tex("H","_A"),Tex("H","_B"),Tex("H","_C"),Tex("M","_A"),Tex("M","_B"),Tex("M","_C"),Tex("A","'"),Tex("B","'"),Tex("C","'")).scale(0.5)
        for i in range(9):
            Relist[i].move_to(VG[i])
        self.wait()
        self.play(*[TransformMatchingTex(a,b) for a,b in zip(VG[:9],Relist[:9])])
        text3=TexText("所以说三角形三边中点，三高垂足，垂心与顶点连线中点，九点共圆！",tex_to_color_map={"三边中点":GREEN,"垂足":GREEN,"连线中点":BLUE}).to_edge(DOWN).set_width(14)
        self.wait()
        self.play(Write(text3),FadeOut(text2))
        self.wait(5)
        self.play(*[FadeOut(i) for i in [circle,Relist[:9],Relist[-9:],mids,midA,H,feet,foot,HVmids,A,B,C]])
        self.wait()
        self.play(FadeOut(text3))

class RandomScene(Scene):
    def construct(self):
        t=MyTrianglePro(np.array([-2,-1,0]),np.array([2,-1,0]),np.array([1,2,0]),color=BLUE,fill_opacity=0.5,stroke_width=5)
        heights=t.get_heights().set_color(WHITE)
        heights1=VGroup(*[Line(t.get_orthocenter(),i) for i in t.get_vertices()])
        feet=VGroup(*[SmallDot(i,color=GREEN) for i in t.get_drop_feet()])
        mids=VGroup(*[SmallDot(i,color=GREEN) for i in t.get_midpoints()])
        ver=VGroup(*[SmallDot(i/2+t.get_orthocenter()/2,color=BLUE) for i in t.get_vertices()])
        垂心=Dot(t.get_orthocenter(),color=GREEN)
        cir=t.get_O9Circle()

        self.add(t,heights,heights1,cir,feet,mids,ver,垂心)
        self.play(*[i.animate.scale(2) for i in [*feet,*mids,*ver]])
        
        self.add(t,heights,heights1,cir,feet,mids,ver,垂心)

        heights.add_updater(lambda m:m.become(t.get_heights().set_color(WHITE)))
        heights1.add_updater(lambda m:m.become(VGroup(*[Line(t.get_orthocenter(),i) for i in t.get_vertices()])))
        feet.add_updater(lambda m:m.become(VGroup(*[Dot(i,color=GREEN) for i in t.get_drop_feet()])))
        mids.add_updater(lambda m:m.become(VGroup(*[Dot(i,color=GREEN) for i in t.get_midpoints()])))
        ver.add_updater(lambda m:m.become(VGroup(*[Dot(i/2+t.get_orthocenter()/2,color=BLUE) for i in t.get_vertices()])))
        垂心.add_updater(lambda m:m.move_to(t.get_orthocenter()))
        cir.add_updater(lambda m:m.become(t.get_O9Circle()))

        for i in range(30):
            self.play(t.animate.become(MyTrianglePro(*[rdarray(-FRAME_X_RADIUS,FRAME_X_RADIUS,-FRAME_Y_RADIUS,FRAME_Y_RADIUS)/2 for i in range(3)],color=BLUE,fill_opacity=0.5,stroke_width=5)))

